//定义：为一个对象提供一个代用品或占位符 以便控制对它的访问
//核心：当用户不方便 直接访问一个对象 或者不满足需要的时候 提供一个替身对象 来控制对这个对象的访问，客户实际上访问的是 替身对象
       //替身对象对请求做出一些处理后 再把请求转交给本体对象
       //代理和本体的接口具有一致性，本体定义了关键功能 而代理是提供或拒绝对它的访问 或者在访问本体之前做一些额外的事情
//实现
 //代理模式主要有三种：保护代理，虚拟代理，缓存代理

 //保护代理主要实现了访问主题的限制行为，以过滤字符为例
 //它的意图很明显 在访问本体之前进行控制 没有消息直接在代理中返回 拒绝访问主体 这数据保护代理的形式 
 //有消息的时候对敏感字符进行处理 这属于虚拟代理的模式 加入了一些额外的操作 在滚动事件触发的时候 也许不需要频繁触发 可以引入函数防抖节流 也是一种虚拟代理的实现

 function sendMsg(msg){
     console.log(msg)
 }

 //代理 对消息进行过滤
 function proxySendMsg(msg){
     //无消息则直接返回
     if(typeof msg === 'undefined'){
         console.log('没有输入消息')
         return;
     }
     //有消息 则进行过滤
     msg = ('' + msg).replace(/泥\s*煤/g,'');

     sendMsg(msg);
 }

 sendMsg('泥煤呀泥 煤呀');//泥煤呀泥 煤呀
 proxySendMsg('泥煤呀泥 煤呀')//呀呀
 proxySendMsg()//没有输入消息

 //函数 防抖  频繁操作中不处理 直到操作完成之后 再过delay的时间 才一次性处理
function debounce(fn,delay){
    delay = delay ||200;
    var timer =null;

    return function(){
        var arg = arguments;
        //每次操作时 清除上次的定时器
        clearTimeout(timer);
        timer = null;

        //定义新的定时器 一段时间后进行操作
        timer = setTimeout(function(){
            fn.apply(this,arg);
        },delay)
    }
}
//函数节流 第一次调用不延迟执行 以后的调用需要延迟指定时间后再次执行
function throttle(fn,delay){
    delay = delay || 500;
    var timer = null,first = true;
    return function(){
        if(first){
            fn.apply(this,arguments)
            return first = false
        }
        if(timer){
            return false
        }
        timer = setTimeout(()=>{
            clearTimeout(timer);
            timer = null;
            fn.apply(this,arguments)
        },delay)
    }
}
var count = 0;
//主体
function scrollHandle(e){
    console.log(e.type,++count);
}
//
function resizeHandle(e){
    console.log('缩放',count++);
}
//代理
var proxyScrollHandle = (function(){
    
    return debounce(scrollHandle,500)
})();
var proxyResizeHandle = (function(){
    
    return debounce(resizeHandle,500)
})();

//缓存代理 可以为一些开销大的运算结果提供暂时的缓存 提升效率

function add(){
    var arg = [].slice.call(arguments);
    return arg.reduce(function(a,b){
        return a+ b;
    })
}

//代理
var proxyAdd = (function(){
    var cache = [];
    return function(){
        var arg = [].slice.call(arguments).join(',');
        // console.log(arg,'arg')
        //如果有 则直接从缓存返回
        if(cache[arg]){
            
            return cache[arg]
        }else{
            
            var ret = add.apply(this,arguments);
            cache[arg] = ret
            return ret;
        }
    }
})()

console.log(
    add(1,2,3,4),
    add(1,2,3,4),
    proxyAdd(10,20,30,40),
    proxyAdd(10,20,30,40)
)//10 10 100 100 但是add函数只执行三次


/**************** 计算乘积 *****************/ 
var mult = function(){ 
    var a = 1; 
    for ( var i = 0, l = arguments.length; i < l; i++ ){ 
    a = a * arguments[i]; 
    } 
    return a; 
   }; 
   /**************** 计算加和 *****************/ 
   var plus = function(){ 
    var a = 0; 
    for ( var i = 0, l = arguments.length; i < l; i++ ){ 
    a = a + arguments[i]; 
    } 
    return a; 
   }; 
   /**************** 创建缓存代理的工厂 *****************/ 
   var createProxyFactory = function( fn ){ 
    var cache = {}; 
    return function(){ 
    var args = Array.prototype.join.call( arguments, ',' ); 
    if ( args in cache ){ 
    return cache[ args ]; 
    } 
    return cache[ args ] = fn.apply( this, arguments ); 
    } 
   }; 
   var proxyMult = createProxyFactory( mult ), 
   proxyPlus = createProxyFactory( plus ); 
   console.log( proxyMult( 1, 2, 3, 4 ) ); // 输出：24 
   console.log ( proxyMult( 1, 2, 3, 4 ) ); // 输出：24 
   console.log ( proxyPlus( 1, 2, 3, 4 ) ); // 输出：10 
   console.log ( proxyPlus( 1, 2, 3, 4 ) ); // 输出：10